/*
 * 这是最简单的字符集加密解密类
 *
 * 给定一个字符集,如['a', 'b', 'c'],把它对应成数字.
 * 能处理的字符串都不能超出这个字符集,无论是原字符串还是密码字符串
 * 
 * 构造方法:constructor(charSet), 是给定的字符集.
 * 然后可以写各种加密解密方法.这里只写最简单的一个,线性加密解密.就是按顺序用密码
 * 的字符串对原文偏移了.
 * 
 * this._charSet:字符集,是一个列表.同时允许用特地的字符串表示某些字符集.
 *   这里只设定一个'base64'字符集.
 * this._length:字符集长度
 * _char2Num(char):字符转为数字,不在字符集中,返回-1
 * _num2Char(num):数字转为字符,数字长度不对,返回空字符串
 * _makeBase64CharSet():返回一个base64字符集,不包括=,所以是64个字符
 * checkString(str1):检查一个字符串str1是否真字符集中,失败返回false
 * encodeLine(src, sn):对src字符串用sn进行线性加密编码,失败返回空字符串
 * decodeLine(src, sn):对src字符串用sn进行线性解密编码,失败返回空字符串
 *
 * 最后更新日期: 2019-06-12 10:58
 */

/* 我的编码类 */
class setycyasCoder {
  
  constructor(charSet) {
    if (charSet == 'base64'){
      this._charSet = this._makeBase64CharSet();
    }else{
      this._charSet = charSet.slice();
    }
    this._length = this._charSet.length;
  }
  
  _makeBase64CharSet(){
    let result = new Array(64);
    // 生成A-Z,a-z
    for(let i = 0;i < 26;i++){
      result[i] = String.fromCharCode(65+i);
      result[i+26] = String.fromCharCode(97+i); 
    }
    // 生成0-9
    for(let i = 0;i < 10;i++){
      result[52+i] = String.fromCharCode(48+i);
    }
    // 生成+/=
    result[62] = '+';result[63] = '/';
    // 完成
    return result;
  }
  
  _char2Num(char){
    return this._charSet.indexOf(char);
  }
  
  _num2Char(num){
    if((num < 0) || (num > this._length-1)){
      return '';
    }else{
      return this._charSet[num];
    }
  }
  
  checkString(str1){
    for(let i = 0;i < str1.length;i++){
      if(this._char2Num(str1[i]) < 0)
        return false;
    }
    return true;
  }
  
  encodeLine(src, sn){
    // 检查字符合法性
    if((!this.checkString(src)) || (!this.checkString(sn)))
      return '';
    // 原字符串变成数字数组,密码变成数字数组,制作结果字符数组
    let srcArray = new Array(src.length);
    let snArray = new Array(sn.length);
    let resultArray = new Array(src.length);
    for(let i = 0;i < srcArray.length;i++){
      srcArray[i] = this._char2Num(src[i]);
    }
    for(let i = 0;i < snArray.length;i++){
      snArray[i] = this._char2Num(sn[i]);
    }
    for(let i = 0;i < resultArray.length;i++){
      let num = (srcArray[i]+snArray[i % snArray.length]) % this._length;
      resultArray[i] = this._num2Char(num);
    }
    // 计算完成
    return resultArray.join('');
  }
  
  decodeLine(src, sn){
    // 检查字符合法性
    if((!this.checkString(src)) || (!this.checkString(sn)))
      return '';
    // 原字符串变成数字数组,密码变成数字数组,制作结果字符数组
    let srcArray = new Array(src.length);
    let snArray = new Array(sn.length);
    let resultArray = new Array(src.length);
    for(let i = 0;i < srcArray.length;i++){
      srcArray[i] = this._char2Num(src[i]);
    }
    for(let i = 0;i < snArray.length;i++){
      snArray[i] = this._char2Num(sn[i]);
    }
    for(let i = 0;i < resultArray.length;i++){
      let num = (this._length+srcArray[i]-snArray[i % snArray.length]) % this._length;
      resultArray[i] = this._num2Char(num);
    }
    // 计算完成
    return resultArray.join('');
  }
  
}

/* 测试 */
var myCoder = new setycyasCoder('base64');
var srcString = '55TGHc+/0556';
var sn = 'AzumaSuzuka';
var encodeString = myCoder.encodeLine(srcString, sn);
var decodeString = myCoder.decodeLine(encodeString, sn);
alert(encodeString+'\n'+decodeString);
